// LemCoop
// Copyright (C) 2013  Oliver Naumann <bldrax@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "levelloader.h"

LevelLoader::LevelLoader(Level* level)
{
	m_level = level;
}

bool LevelLoader::LoadLevel(std::string xml_data)
{
	std::vector<char> buffer(xml_data.begin(), xml_data.end());
	buffer.push_back(0);
	std::cout << xml_data;

	// Parse the xml data.
	rapidxml::xml_document<> doc;
	doc.parse<0>(&buffer[0]);

	// Get property node.
	rapidxml::xml_node<>* root = doc.first_node();
	rapidxml::xml_node<>* node = root->first_node("Properties");

	m_level->id = boost::lexical_cast<int>(node->first_node("ID")->value());
	m_level->number = boost::lexical_cast<int>(node->first_node("Number")->value());
	m_level->title = node->first_node("Title")->value();
	m_level->player_number = boost::lexical_cast<int>(node->first_node("PlayerNumber")->value());
	m_level->lems_to_save = boost::lexical_cast<int>(node->first_node("LemsToSave")->value());

	// Get the size of the level.
	m_level->size_x = boost::lexical_cast<int>(node->first_node("Size_X")->value());
	m_level->size_y = boost::lexical_cast<int>(node->first_node("Size_Y")->value());

	// Get players node. We now set the player info.
	node = root->first_node("Players");
	rapidxml::xml_node<> *player_node = node->first_node();
	for (int i = 0; i < m_level->player_number; i++)
	{
		Player new_player;

		// TODO: Load player related stuff here, like number of actions, ...
		new_player.number_of_lems = 0;

		m_level->player_info.push_back(new_player);
		player_node = player_node->next_sibling();
	}

	// Load the entries
	node = root->first_node("Entries");
	for (rapidxml::xml_node<> *entry_node = node->first_node(); entry_node; entry_node = entry_node->next_sibling())
	{
		int player_number = boost::lexical_cast<int>(entry_node->first_node("Player")->value());
		std::string type = entry_node->first_node("Type")->value();
		int x = boost::lexical_cast<int>(entry_node->first_node("X")->value());
		int y = boost::lexical_cast<int>(entry_node->first_node("Y")->value());
		int time = boost::lexical_cast<int>(entry_node->first_node("Time")->value());
		int lems_to_spawn = boost::lexical_cast<int>(entry_node->first_node("LemsToSpawn")->value());

		// Add the number of lems to spawn to the number of lems that spawn for a player.
		m_level->player_info.at(player_number - 1).number_of_lems += lems_to_spawn;
		m_level->number_of_lems += lems_to_spawn;

		Entry* entry = new Entry(player_number, type, x, y, time, lems_to_spawn);
		m_level->entries.push_back(entry);
	}

	// Get tile node.
	node = root->first_node("Tiles");

	// Create the graphics and ground mask for the level so they can be filled in the following.
	ALLEGRO_BITMAP* graphics = al_create_bitmap(m_level->size_x, m_level->size_y);
	GroundMask* mask = new GroundMask(m_level->size_x, m_level->size_y);

	// Precalculate the mask colors.
	ALLEGRO_COLOR type_colors[4] =
	{
		al_map_rgb(LEVEL_MASK_COLORS[0][0], LEVEL_MASK_COLORS[0][1], LEVEL_MASK_COLORS[0][2]),
		al_map_rgb(LEVEL_MASK_COLORS[1][0], LEVEL_MASK_COLORS[1][1], LEVEL_MASK_COLORS[1][2]),
		al_map_rgb(LEVEL_MASK_COLORS[2][0], LEVEL_MASK_COLORS[2][1], LEVEL_MASK_COLORS[2][2]),
		al_map_rgb(LEVEL_MASK_COLORS[3][0], LEVEL_MASK_COLORS[3][1], LEVEL_MASK_COLORS[3][2])
	};

	// Go through all tiles an draw them / store the mask.
	for(rapidxml::xml_node<> *tile_node = node->first_node("Tile"); tile_node; tile_node = tile_node->next_sibling())
	{
		// Where is the tile located?
		int pos_x = boost::lexical_cast<int>(tile_node->first_node("Pos_X")->value());
		int pos_y = boost::lexical_cast<int>(tile_node->first_node("Pos_Y")->value());

		// Get the identifiers for the graphics and the mask of the tile...
		std::string graphics_id = tile_node->first_node("Graphics")->value();
		std::string mask_id = tile_node->first_node("Mask")->value();

		// ...and then their corresponding bitmaps.
		ALLEGRO_BITMAP* graphics_bmp = allegro_bitmap_resource_manager.GetResource(graphics_id);
		ALLEGRO_BITMAP* mask_bmp = allegro_bitmap_resource_manager.GetResource(mask_id);

		//Draw the tile to the level graphics.
		al_set_target_bitmap(graphics);
		al_draw_bitmap(graphics_bmp, pos_x, pos_y, NULL);

		// Use the mask of the tile to contribute to the mask of the level.
		al_lock_bitmap(mask_bmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY);
		for (int x = 0; x < al_get_bitmap_width(mask_bmp); x++)
		{
			for (int y = 0; y < al_get_bitmap_height(mask_bmp); y++)
			{
				// Color of the current pixel.
				ALLEGRO_COLOR mask_pixel_color = al_get_pixel(mask_bmp, x, y);

				// Is it the color for air? Then do nothing.
				if (mask_pixel_color.r == type_colors[0].r &&
					mask_pixel_color.g == type_colors[0].g &&
					mask_pixel_color.b == type_colors[0].b)
				{
					continue;
				}

				// If it is not air, find out that it is and set the pixel in the mask.
				for (int type = 1; type < 4; type++)
				{
					if (mask_pixel_color.r == type_colors[type].r &&
						mask_pixel_color.g == type_colors[type].g &&
						mask_pixel_color.b == type_colors[type].b)
					{
						// TODO: Out of bounds checking?
						mask->SetPixel(pos_x + x, pos_y + y, type);
						break;
					}
				}
			}
		}
	}

	m_level->set_graphics(graphics);
	m_level->set_mask(mask);

	return true;
}